﻿using System;
using System.Collections.Generic;
using StockholmsStad.Utilities.Enums;
using StockholmsStad.Utilities.Exceptions;
using StockholmsStad.Runtime.Serialization.DataContract;
using StockholmsStad.Runtime.Serialization.DataContract.Enums;
using System.Reflection;

namespace StockholmsStad.Business
{
    /// <summary>
    /// Hanterar affärslogik för underhållning
    /// </summary>
    public class MaintenanceBusiness : BusinessBase
    {
        private const bool useTransaction = true;

        /// <summary>
        /// Skapar business-objektet för underhållsdelen
        /// </summary>
        /// <param name="user"></param>
        public MaintenanceBusiness(User user)
            : base(user)
        {

        }

        ///<summary>
        /// Uppdaterar befintliga tidsblock eller lägger till ett nytt om det inte finns. 
        ///</summary>
        ///<param name="timeBlocks">En lista med tidsblock (<see cref="MinisterTimeBlock"/>) som ska läggas till. </param>
        ///<returns>Den uppdaterade listan med tidsblock.</returns>
        public List<MinisterTimeBlock> UpdateTimeBlocks(List<MinisterTimeBlock> timeBlocks)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            var agent = AgentFactory.GetMaintenanceAgent();

            using (var context = GetDataContext(useTransaction))
            {
                foreach (var timeBlock in timeBlocks)
                {
                    if (timeBlock.TimeBlockId.HasValue)
                    {
                        agent.UpdateTimeBlock(context, timeBlock);
                    }
                    else
                    {
                        var id = agent.AddTimeBlock(context, timeBlock);
                        timeBlock.TimeBlockId = id;
                    }

                }

                context.TransactionComplete();
                return timeBlocks;
            }
        }

        ///<summary>
        /// Lägger till nya tidsblock, om ett tidsblock skulle existera (dvd krock uppstår) uppdateras 
        /// detta.
        ///</summary>
        ///<returns>Den uppdaterade listan med tidsblock.</returns>
        public List<MinisterTimeBlock> GetTimeBlocks()
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(false))
            {
                var agent = AgentFactory.GetMaintenanceAgent();
                return agent.GetTimeBlocks(context);
            }
        }

        ///<summary>
        /// Hämtar tidsblock för ett visst datum
        ///</summary>
        ///<param name="date">Det datum för vilket tidsblock ska hämtas (<see cref="MinisterTimeBlock"/>). </param>
        ///<returns>Listan med tidsblock.</returns>
        public List<MinisterTimeBlock> GetTimeBlocks(DateTime date)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(false))
            {
                var agent = AgentFactory.GetMaintenanceAgent();
                return agent.GetTimeBlocks(context, date);
            }
        }

        /// <summary>
        /// Lägger till en nya text
        /// </summary>
        /// <param name="text">Texten (<see cref="InformationText"/>) som ska läggas till. </param>
        /// <returns>Nyckeln på den tillagda texten. </returns>
        public int AddText(InformationText text)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(useTransaction))
            {
                var agent = AgentFactory.GetMaintenanceAgent();
                var id = agent.AddText(context, text);
                context.TransactionComplete();
                return id;
            }
        }

        /// <summary>
        /// Sparar text
        /// </summary>
        /// <param name="text">Texten (<see cref="InformationText"/>) som ska sparas. </param>
        public void UpdateText(InformationText text)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(useTransaction))
            {
                var agent = AgentFactory.GetMaintenanceAgent();
                agent.UpdateText(context, text);
                context.TransactionComplete();
            }
        }

        /// <summary>
        /// Tar bort text
        /// </summary>
        /// <param name="text">Texten (<see cref="InformationText"/>) som ska tas bort. </param>
        public void DeleteText(InformationText text)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(useTransaction))
            {
                var agent = AgentFactory.GetMaintenanceAgent();
                agent.DeleteText(context, text);
                context.TransactionComplete();
            }
        }

        /// <summary>
        /// Hämtar all texter
        /// </summary>
        /// <param name="textId">Id-värdet på den text som ska hämtas. </param>
        /// <returns>En lista med texter (<see cref="InformationText"/>).</returns>
        public InformationText GetText(int textId)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(false))
            {
                var agent = AgentFactory.GetMaintenanceAgent();
                return agent.GetText(context, textId);
            }
        }

        /// <summary>
        /// Hämtar all texter för en viss typ. 
        /// </summary>
        /// <param name="textTypeId">Den typ av text som ska hämtas. </param>
        /// <returns>En lista med texter (<see cref="InformationText"/>).</returns>
        public List<InformationText> GetTexts(int textTypeId)
        {
            using (var context = GetDataContext(false))
            {
                var agent = AgentFactory.GetMaintenanceAgent();
                return agent.GetTexts(context, textTypeId);
            }
        }

        /// <summary>
        /// Hämtar all texttyper
        /// </summary>
        /// <returns>En lista med texttyper (<see cref="ValueIdPair"/>).</returns>
        public List<ValueIdPair> GetTextTypes()
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(false))
            {
                var agent = AgentFactory.GetMaintenanceAgent();
                return agent.GetTextTypes(context);
            }
        }

        ///<summary>
        /// Hämtar alla tillgängliga språk
        ///</summary>
        ///<returns></returns>
        ///<exception cref="StockholmStadSystemException"></exception>
        public List<ValueIdPair> GetLanguages()
        {
            using (var context = GetDataContext(false))
            {
                var agent = AgentFactory.GetLanguageAgent();
                return agent.GetLanguages(context);
            }            
        }


        ///<summary>
        /// Lägger till ett nytt behov
        ///</summary>
        ///<param name="name">Namn på behovet</param>
        ///<returns>Behovets id-värde</returns>
        ///<exception cref="StockholmStadSystemException"></exception>
        public int AddSpecialNeed(string name)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(useTransaction))
            {
                var agent = AgentFactory.GetCeremonyAgent();
                var id = agent.AddSpecialNeed(context, name);
                context.TransactionComplete();
                return id;
            }
        }

        ///<summary>
        /// Lägger till ett nytt ceremonispråk
        ///</summary>
        ///<param name="language">Namn på språket</param>
        ///<returns>Språkets id-värde</returns>
        ///<exception cref="StockholmStadSystemException"></exception>
        public int AddCeremonyLanguage(string language)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(true))
            {
                var agent = AgentFactory.GetLanguageAgent();
                var id = agent.AddCeremonyLanguage(context, language);
                context.TransactionComplete();
                return id;
            }
        }

        ///<summary>
        /// Lägger till ett nytt certifikatspråk
        ///</summary>
        ///<param name="languageName">Namn på språket</param>
        ///<returns>Språkets id-värde</returns>
        ///<exception cref="StockholmStadSystemException"></exception>
        public int AddCertificateLanguage(string languageName)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(true))
            {
                var agent = AgentFactory.GetLanguageAgent();
                var id = agent.AddCertificateLanguage(context, languageName);

                context.TransactionComplete();
                return id;
            }
        }

        ///<summary>
        /// Lägger till ett nytt språk
        ///</summary>
        ///<param name="languageName">Namn på språket</param>
        ///<returns>Språkets id-värde</returns>
        ///<exception cref="StockholmStadSystemException"></exception>
        public int AddLanguage(string languageName)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(true))
            {
                var agent = AgentFactory.GetLanguageAgent();
                var id = agent.AddLanguage(context, languageName);
                context.TransactionComplete();
                return id;
            }
        }

        ///<summary>
        /// Uppdaterar ett språk
        ///</summary>
        ///<param name="language">Språket</param>
        ///<returns></returns>
        ///<exception cref="StockholmStadSystemException"></exception>
        public void UpdateLanguage(ValueIdPair language)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(true))
            {
                var agent = AgentFactory.GetLanguageAgent();
                agent.UpdateLanguage(context, language);
                context.TransactionComplete();
            }
        }

        ///<summary>
        /// tar bort ett språk
        ///</summary>
        ///<param name="language">Språket</param>
        ///<returns></returns>
        ///<exception cref="StockholmStadSystemException"></exception>
        public void DeleteLanguage(ValueIdPair language)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(true))
            {
                var agent = AgentFactory.GetLanguageAgent();
                agent.DeleteLanguage(context, language);
                context.TransactionComplete();
            }
        }

        ///<summary>
        /// Tar bort ett ceremoni språk
        ///</summary>
        ///<param name="language">Språket</param>
        ///<returns></returns>
        ///<exception cref="StockholmStadSystemException"></exception>
        public void DeleteCeremonyLanguage(ValueIdPair language)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(true))
            {
                var agent = AgentFactory.GetLanguageAgent();
                agent.DeleteCeremonyLanguage(context, language);
                context.TransactionComplete();
            }
        }

        ///<summary>
        /// Tar bort ett certifikat språk
        ///</summary>
        ///<param name="language">Språket</param>
        ///<returns></returns>
        ///<exception cref="StockholmStadSystemException"></exception>
        public void DeleteCertificateLanguage(ValueIdPair language)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(true))
            {
                var agent = AgentFactory.GetLanguageAgent();
                agent.DeleteCertificateLanguage(context, language);
                context.TransactionComplete();
            }
        }

        /// <summary>
        /// Hämtar alla "lediga" språk för en viss typ av certifikat. 
        /// </summary>
        /// <param name="certificateType">Anger vilken typ som tillgängliga språk finns för. </param>
        /// <returns>En lista med språk (<see cref="ValueIdPair"/>).</returns>
        public List<ValueIdPair> GetAvailableLanguagesForReportDefinition(MarriageCertificateType certificateType)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(false))
            {
                var agent = AgentFactory.GetMaintenanceAgent();
                return agent.GetAvailableLanguagesForReportDefinition(context, certificateType);
            }            
        }

        /// <summary>
        /// Hämtar alla tillgängliga språk för en viss typ av certifikat. 
        /// </summary>
        /// <param name="certificateType">Anger vilken typ som tillgängliga språk finns för. </param>
        /// <returns>En lista med språk (<see cref="ValueIdPair"/>).</returns>
        public List<ValueIdPair> GetLanguagesForCertificateType(MarriageCertificateType certificateType)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(false))
            {
                var agent = AgentFactory.GetMaintenanceAgent();
                return agent.GetLanguagesForCertificateType(context, certificateType);
            }
        }

        /// <summary>
        /// Skapar en ny rapportdefinition (en rapport med nytt språk och innehåll). 
        /// </summary>
        /// <param name="certificate">Innehållet på den nya rapportdefinitionen. </param>
        /// <returns>Id-numret på den tillagda rapportdefinitionen. </returns>
        public int AddMarriageCertificate(MarriageCertificate certificate)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(useTransaction))
            {
                var agent = AgentFactory.GetMaintenanceAgent();
                var id = agent.AddMarriageCertificate(context, certificate);
                context.TransactionComplete();
                return id;
            }
        }

        /// <summary>
        /// Uppdaterar en befintlig rapportdefinition. 
        /// </summary>
        /// <param name="certificate">Innehållet på rapportdefinitionen. </param>
        /// <returns> </returns>
        public void UpdateMarriageCertificate(MarriageCertificate certificate)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(useTransaction))
            {
                var agent = AgentFactory.GetMaintenanceAgent();
                agent.UpdateMarriageCertificate(context, certificate);
                context.TransactionComplete();
            }
        }

        /// <summary>
        /// Tar bort en rapportdefinition
        /// </summary>
        /// <param name="certificate">Innehållet på rapportdefinitionen. </param>
        /// <returns> </returns>
        public void DeleteMarriageCertificate(MarriageCertificate certificate)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(useTransaction))
            {
                var agent = AgentFactory.GetMaintenanceAgent();
                agent.DeleteMarriageCertificate(context, certificate);
                context.TransactionComplete();
            }
        }

        /// <summary>
        /// Hämtar ett registreringsbevis. 
        /// </summary>
        /// <param name="marriageCertificateType">Id-numret på det aktuella beviset. </param>
        /// <param name="languageId">Id-numret på det aktuella beviset. </param>
        /// <returns>Registreringsbeviset. </returns>
        public MarriageCertificate GetMarriageCertificate(MarriageCertificateType marriageCertificateType, int languageId)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(false))
            {
                var agent = AgentFactory.GetMaintenanceAgent();
                return agent.GetMarriageCertificate(context, marriageCertificateType, languageId);
            }
        }

        /// <summary>
        /// Uppdaterar affärsregler. 
        /// </summary>
        /// <param name="properties">De regler som ska uppdateras. </param>
        public void SetProperties(ParVisProperties properties)
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(useTransaction))
            {
                var agent = AgentFactory.GetPropertiesAgent();
                agent.SetProperties(context, properties);
                context.TransactionComplete();
            }
        }

        /// <summary>
        /// Hämtar befintliga affärsregler
        /// </summary>
        /// <returns>De regler som gäller. </returns>
        public ParVisProperties GetProperties()
        {
            if (CurrentUser.Role != UserRole.SysAdmin && CurrentUser.Role != UserRole.SuperUser)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (var context = GetDataContext(false))
            {
                var agent = AgentFactory.GetPropertiesAgent();
                return agent.GetProperties(context);
            }            
        }

        /// <summary>
        /// Hämtar alla par som kan avpersonifieras.
        /// </summary>
        /// <returns>En lista med alla par som kan avpersonifieras.. </returns>
        public IList<Couple> GetCouplesForDepersonation(DateTime fromDate, DateTime toDate)
        {
            using (var context = GetDataContext(false))
            {
                var agent = AgentFactory.GetMaintenanceAgent();
                return agent.GetCouplesForDepersonation(context, fromDate, toDate);
            }
        }

        /// <summary>
        /// Hämtar alla par som kan avpersonifieras.
        /// </summary>
        /// <returns>En lista med alla par som kan avpersonifieras.. </returns>
        public int DepersonateCouples(List<Couple> couples)
        {
            using (var context = GetDataContext(false))
            {
                var agent = AgentFactory.GetMaintenanceAgent();
                return agent.DepersonateCouples(context, couples);
            }
        }

        /// <summary>
        /// Hämtar databasens version.
        /// </summary>
        /// <returns>Ett versionsnummer</returns>
        public string GetDatabaseVersion()
        {
            using (var context = GetDataContext(false))
            {
                var agent = AgentFactory.GetMaintenanceAgent();
                var version = agent.GetDatabaseVersion(context);
                return version != null ? version.VersionName : "";
            }
        }

        /// <summary>
        /// Hämtar tjänstelagrets version.
        /// </summary>
        /// <returns>Ett versionsnummer </returns>
        public string GetServiceVersion()
        {
            return Assembly.GetExecutingAssembly().GetName().Version.ToString(); ;
        }
    }
}